home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / TCPUSER.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  8KB  |  376 lines

  1. /* User calls to TCP */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "timer.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "internet.h"
  9. #include "tcp.h"
  10. #include "ip.h"
  11. #include "icmp.h"
  12. #include "proc.h"
  13.  
  14. int16 Tcp_window = DEF_WND;
  15.  
  16. struct tcb *
  17. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  18. struct socket *lsocket;    /* Local socket */
  19. struct socket *fsocket;    /* Remote socket */
  20. int mode;        /* Active/passive/server */
  21. int16 window;        /* Receive window (and send buffer) sizes */
  22. void (*r_upcall)();    /* Function to call when data arrives */
  23. void (*t_upcall)();    /* Function to call when ok to send more data */
  24. void (*s_upcall)();    /* Function to call when connection state changes */
  25. int tos;
  26. int user;        /* User linkage area */
  27. {
  28.     struct connection conn;
  29.     register struct tcb *tcb;
  30.  
  31.     if(lsocket == NULLSOCK){
  32.         Net_error = INVALID;
  33.         return NULLTCB;
  34.     }
  35.     conn.local.address = lsocket->address;
  36.     conn.local.port = lsocket->port;
  37.     if(fsocket != NULLSOCK){
  38.         conn.remote.address = fsocket->address;
  39.         conn.remote.port = fsocket->port;
  40.     } else {
  41.         conn.remote.address = 0;
  42.         conn.remote.port = 0;
  43.     }
  44.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  45.         if((tcb = create_tcb(&conn)) == NULLTCB){
  46.             Net_error = NO_MEM;
  47.             return NULLTCB;
  48.         }
  49.     } else if(tcb->state != LISTEN){
  50.         Net_error = CON_EXISTS;
  51.         return NULLTCB;
  52.     }
  53.     tcb->user = user;
  54.     if(window != 0)
  55.         tcb->window = tcb->rcv.wnd = window;
  56.     else
  57.         tcb->window = tcb->rcv.wnd = Tcp_window;
  58.     tcb->snd.wnd = 1;    /* Allow space for sending a SYN */
  59.     tcb->r_upcall = r_upcall;
  60.     tcb->t_upcall = t_upcall;
  61.     tcb->s_upcall = s_upcall;
  62.     tcb->tos = tos;
  63.     switch(mode){
  64.     case TCP_SERVER:
  65.         tcb->flags.clone = 1;
  66.     case TCP_PASSIVE:    /* Note fall-thru */
  67.         setstate(tcb,LISTEN);
  68.         break;
  69.     case TCP_ACTIVE:
  70.         /* Send SYN, go into SYN_SENT state */
  71.         tcb->flags.active = 1;
  72.         send_syn(tcb);
  73.         setstate(tcb,SYN_SENT);
  74.         tcp_output(tcb);
  75.         Tcp_stat.conout++;
  76.         break;
  77.     }
  78.     return tcb;
  79. }
  80. /* User send routine */
  81. int
  82. send_tcp(tcb,bp)
  83. register struct tcb *tcb;
  84. struct mbuf *bp;
  85. {
  86.     int16 cnt;
  87.  
  88.     if(tcb == NULLTCB || bp == NULLBUF){
  89.         free_p(bp);
  90.         Net_error = INVALID;
  91.         return -1;
  92.     }
  93.     cnt = len_mbuf(bp);
  94.     switch(tcb->state){
  95.     case CLOSED:
  96.         free_p(bp);
  97.         Net_error = NO_CONN;
  98.         return -1;
  99.     case LISTEN:
  100.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  101.             /* Save data for later */
  102.             append(&tcb->sndq,bp);
  103.             tcb->sndcnt += cnt;
  104.             break;
  105.         }        
  106.         /* Change state from passive to active */
  107.         tcb->flags.active = 1;
  108.         send_syn(tcb);
  109.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  110.     case SYN_SENT:
  111.     case SYN_RECEIVED:
  112.     case ESTABLISHED:
  113.     case CLOSE_WAIT:
  114.         append(&tcb->sndq,bp);
  115.         tcb->sndcnt += cnt;
  116.         tcp_output(tcb);
  117.         break;
  118.     case FINWAIT1:
  119.     case FINWAIT2:
  120.     case CLOSING:
  121.     case LAST_ACK:
  122.     case TIME_WAIT:
  123.         free_p(bp);
  124.         Net_error = CON_CLOS;
  125.         return -1;
  126.     }
  127.     return cnt;
  128. }
  129. /* User receive routine */
  130. int
  131. recv_tcp(tcb,bpp,cnt)
  132. register struct tcb *tcb;
  133. struct mbuf **bpp;
  134. int16 cnt;
  135. {
  136.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  137.         Net_error = INVALID;
  138.         return -1;
  139.     }
  140.     if(tcb->rcvcnt == 0){
  141.         /* If there's nothing on the queue, our action depends on what state
  142.          * we're in (i.e., whether or not we're expecting any more data).
  143.          * If no more data is expected, then simply return 0; this is
  144.          * interpreted as "end of file". Otherwise return -1.
  145.          */
  146.         switch(tcb->state){
  147.         case LISTEN:
  148.         case SYN_SENT:
  149.         case SYN_RECEIVED:
  150.         case ESTABLISHED:
  151.         case FINWAIT1:
  152.         case FINWAIT2:
  153.             Net_error = WOULDBLK;
  154.             return -1;
  155.         case CLOSED:
  156.         case CLOSE_WAIT:
  157.         case CLOSING:
  158.         case LAST_ACK:
  159.         case TIME_WAIT:
  160.             *bpp = NULLBUF;
  161.             return 0;
  162.         }
  163.     }
  164.     /* cnt == 0 means "I want it all" */
  165.     if(cnt == 0)
  166.         cnt = tcb->rcvcnt;
  167.     /* See if the user can take all of it */
  168.     if(tcb->rcvcnt <= cnt){
  169.         cnt = tcb->rcvcnt;
  170.         *bpp = tcb->rcvq;
  171.         tcb->rcvq = NULLBUF;
  172.     } else {
  173.         if((*bpp = alloc_mbuf(cnt)) == NULLBUF){
  174.             Net_error = NO_MEM;
  175.             return -1;
  176.         }
  177.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  178.         (*bpp)->cnt = cnt;
  179.     }
  180.     tcb->rcvcnt -= cnt;
  181.     tcb->rcv.wnd += cnt;
  182.     /* Do a window update if it was closed */
  183.     if(cnt == tcb->rcv.wnd){
  184.         tcb->flags.force = 1;
  185.         tcp_output(tcb);
  186.     }
  187.     return cnt;
  188. }
  189. /* This really means "I have no more data to send". It only closes the
  190.  * connection in one direction, and we can continue to receive data
  191.  * indefinitely.
  192.  */
  193. int
  194. close_tcp(tcb)
  195. register struct tcb *tcb;
  196. {
  197.     if(tcb == NULLTCB){
  198.         Net_error = INVALID;
  199.         return -1;
  200.     }
  201.     switch(tcb->state){
  202.     case CLOSED:
  203.         return 0;    /* Unlikely */
  204.     case LISTEN:
  205.     case SYN_SENT:
  206.         close_self(tcb,NORMAL);
  207.         return 0;
  208.     case SYN_RECEIVED:
  209.     case ESTABLISHED:
  210.         tcb->sndcnt++;
  211.         tcb->snd.nxt++;
  212.         setstate(tcb,FINWAIT1);
  213.         tcp_output(tcb);
  214.         return 0;
  215.     case CLOSE_WAIT:
  216.         tcb->sndcnt++;
  217.         tcb->snd.nxt++;
  218.         setstate(tcb,LAST_ACK);
  219.         tcp_output(tcb);
  220.         return 0;
  221.     case FINWAIT1:
  222.     case FINWAIT2:
  223.     case CLOSING:
  224.     case LAST_ACK:
  225.     case TIME_WAIT:
  226.         Net_error = CON_CLOS;
  227.         return -1;
  228.     }
  229.     return -1;    /* "Can't happen" */
  230. }
  231. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  232.  * not in the CLOSED state. This function should normally be called by the
  233.  * user only in response to a state change upcall to CLOSED state.
  234.  */
  235. int
  236. del_tcp(tcb)
  237. register struct tcb *tcb;
  238. {
  239.     struct reseq *rp,*rp1;
  240.  
  241.     if(tcb == NULLTCB){
  242.         Net_error = INVALID;
  243.         return -1;
  244.     }
  245.     unlink_tcb(tcb);
  246.     stop_timer(&tcb->timer);
  247.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  248.         rp1 = rp->next;
  249.         free_p(rp->bp);
  250.         free((char *)rp);
  251.     }
  252.     tcb->reseq = NULLRESEQ;
  253.     free_p(tcb->rcvq);
  254.     free_p(tcb->sndq);
  255.     free((char *)tcb);
  256.     return 0;
  257. }
  258. /* Return 1 if arg is a valid TCB, 0 otherwise */
  259. int
  260. tcpval(tcb)
  261. struct tcb *tcb;
  262. {
  263.     register int i;
  264.     register struct tcb *tcb1;
  265.  
  266.     if(tcb == NULLTCB)
  267.         return 0;    /* Null pointer can't be valid */
  268.     for(i=0;i<NTCB;i++){
  269.         for(tcb1=Tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  270.             if(tcb1 == tcb)
  271.                 return 1;
  272.         }
  273.     }
  274.     return 0;
  275. }
  276. /* Kick a particular TCP connection */
  277. int
  278. kick_tcp(tcb)
  279. register struct tcb *tcb;
  280. {
  281.     if(!tcpval(tcb))
  282.         return -1;
  283.     tcp_timeout(tcb);
  284.     return 0;
  285. }
  286. /* Kick all TCP connections to specified address; return number kicked */
  287. int
  288. kick(addr)
  289. int32 addr;
  290. {
  291.     register int i;
  292.     register struct tcb *tcb;
  293.     int cnt = 0;
  294.  
  295.     for(i=0;i<NTCB;i++){
  296.         for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next){
  297.             if(tcb->conn.remote.address == addr){
  298.                 kick_tcp(tcb);
  299.                 cnt++;
  300.             }
  301.         }
  302.     }
  303.     return cnt;
  304. }
  305. /* Clear all TCP connections */
  306. void
  307. reset_all()
  308. {
  309.     register int i;
  310.     register struct tcb *tcb;
  311.  
  312.     for(i=0;i<NTCB;i++){
  313.         for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next)
  314.             reset_tcp(tcb);
  315.     }
  316.     pwait(NULL);    /* Let the RSTs go forth */
  317. }
  318. void
  319. reset_tcp(tcb)
  320. register struct tcb *tcb;
  321. {
  322.     struct tcp fakeseg;
  323.     struct ip fakeip;
  324.  
  325.     if(tcb == NULLTCB)
  326.         return;
  327.     if(tcb->state != LISTEN){
  328.         /* Compose a fake segment with just enough info to generate the
  329.          * correct RST reply
  330.          */
  331.         fakeseg.flags.rst = 0;
  332.         fakeseg.dest = tcb->conn.local.port;
  333.         fakeseg.source = tcb->conn.remote.port;
  334.         fakeseg.flags.ack = 1;
  335.         /* Here we try to pick a sequence number with the greatest likelihood
  336.          * of being in his receive window.
  337.          */
  338.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  339.         fakeip.dest = tcb->conn.local.address;
  340.         fakeip.source = tcb->conn.remote.address;
  341.         fakeip.tos = tcb->tos;
  342.         reset(&fakeip,&fakeseg);
  343.     }
  344.     close_self(tcb,RESET);
  345. }
  346. #ifdef    notused
  347. /* Return character string corresponding to a TCP well-known port, or
  348.  * the decimal number if unknown.
  349.  */
  350. char *
  351. tcp_port(n)
  352. int16 n;
  353. {
  354.     static char buf[32];
  355.  
  356.     switch(n){
  357.     case IPPORT_ECHO:
  358.         return "echo";
  359.     case IPPORT_DISCARD:
  360.         return "discard";
  361.     case IPPORT_FTPD:
  362.         return "ftp_data";
  363.     case IPPORT_FTP:
  364.         return "ftp";    
  365.     case IPPORT_TELNET:
  366.         return "telnet";
  367.     case IPPORT_SMTP:
  368.         return "smtp";
  369.     default:
  370.         sprintf(buf,"%u",n);
  371.         return buf;
  372.     }
  373. }
  374. #endif
  375.  
  376.